ko.extenders.modelUpdated = function(target, sender) {
    
    target.subscribe(function(newValue) {
    	if (sender != null && sender != undefined) {
        if (sender.RowState == undefined) sender.RowState = 'modified';
        else {
          if (sender.RowState != 'added') sender.RowState = 'modified';   
        }
    	}
    });

    return target;
};

ko.extenders.validator = function(target, e) {

  target.hasError = ko.observable();
  target.validationMessage = ko.observable();
  
  function validate() {
    var config = {
      mode: 'string',
      message: 'The value for this field is invalid',
      references: [],
      referenceKey: '',
      saveButton: undefined,
      saveButtonEnable: undefined,
      persistingValue: function() { return null; }
    };

    $.extend(config, e);

    var mode = config.mode;
    var references = config.references;
    var value = null;

    try {
      value = target();
    }
    catch (ex) {

    }

    if (value != null &&
        value != undefined) {
      var hasError = false;
      var message = config.message;

      if (mode == 'string') {
        if (value.toString().trim() == '') hasError = true;
      }
      else if (mode == 'string/empty-allowed') {

      }
      else if (mode == 'password') {
        if (value.toString().trim() == '') hasError = true;
      }
      else if (mode == 'password/empty-allowed') {

      }
      else if (mode == 'email') {
        if (!value.trim().isEmail()) hasError = true;
      }
      else {

      }

      if (!hasError) {
        if (references.length > 0) {
            hasError = true;

            var referenceKey = config.referenceKey;

            if (referenceKey.trim() != '') {
              for (i = 0; i < references.length; i++) {
                var reference = references[i];
                if (reference[referenceKey] == value) {
                  hasError = false; break;
                }
              }
            }
            else {
              for (i = 0; i < references.length; i++) {
                var reference = references[i];
                if (reference == value) {
                  hasError = false; break;
                }
              }
            }
        }
        else hasError = (mode == 'int');
      }

      if (!hasError) {
        var persistingValue = config.persistingValue();

        if (persistingValue != undefined &&
            persistingValue != null) hasError = (value !== persistingValue);
      }
      
      target.hasError(hasError);
      target.validationMessage(message);

      if (config.saveButton != undefined) {
        var saveButton = config.saveButton;

        if (config.saveButtonEnable != undefined) {
          var enabled = true;

          enabled = config.saveButtonEnable();

          if (!enabled) {
            if (!saveButton.hasClass('disabled')) saveButton.addClass('disabled');
          }
          else saveButton.removeClass('disabled');
        }
        else {
          if (hasError) {
            if (!saveButton.hasClass('disabled')) saveButton.addClass('disabled');
          }
          else saveButton.removeClass('disabled');
        }
      } 
    }
  }

  validate();
  target.subscribe(validate);

  return target;
};